package com.amoyt.project.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * JWT工具类 TODO 实现可以放入Map类型数据
 */
@ConfigurationProperties(prefix = "jwt")
@Component
@Data
public class JwtUtil {
    //有效期为
    private Long JWT_TTL;  //从配置文件读取
	//私钥明文
    private String JWT_KEY; //从配置文件读取

    //生成令牌
    private static String getUUID(){
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        return token;
    }


    /**
     * 生成jtw的工具一  不设置过期时间，则采取默认策略 过期时间1小时
     * @param subject （userId） token中要存放的数据（json格式）
     * @return
     */
    public String createJWT(String subject) {
        JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 设置过期时间
        return builder.compact();
    }

    /**
     * 生成jtw的工具二 设置过期时间
     * @param subject token中要存放的数据（json格式）
     * @param ttlMillis token超时时间
     * @return
     */
    public String createJWT(String subject, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 设置过期时间
        return builder.compact();
    }


    /**
     * 核心构建方法1：支持携带额外Map数据
     */
    private JwtBuilder getJwtBuilder(Object subject, Long ttlMillis, String uuid) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; //指定签名算法
        SecretKey secretKey = generalKey(); //获取密钥(加密后的明文)
        long nowMillis = System.currentTimeMillis();//获取到系统当前的时间戳
        Date now = new Date(nowMillis);

        //是否自定义设置过期时间
        if(ttlMillis==null){
            ttlMillis=JWT_TTL;
        }
        long expMillis = nowMillis + ttlMillis;
        Date expDate = new Date(expMillis); //过期时间

        //返回wtBuilder对象
        return Jwts.builder()
                .setId(uuid)                 //唯一的ID
                .setSubject(subject.toString())         // 主题  可以是JSON数据
                .setIssuer("小唐官方平台")     // 签发者
                .setIssuedAt(now)            // 签发时间
                .signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥
                .setExpiration(expDate);     //过期时间
    }



    /**
     * 明文密秘钥加密成密钥
     */
    private SecretKey generalKey() {
        // 1. 将明文密钥转换为字节数组
        byte[] keyBytes = JWT_KEY.getBytes(StandardCharsets.UTF_8);

        // 2. 确保密钥长度为 32 字节（256 位）
        MessageDigest sha256Digest;
        try {
            sha256Digest = MessageDigest.getInstance("SHA-256");
            // 无论原始长度如何，用 SHA-256 哈希生成 32 字节的密钥
            keyBytes = sha256Digest.digest(keyBytes);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("无法生成 SHA-256 哈希", e);
        }

        // 3. 生成符合 HS256 要求的密钥
        return Keys.hmacShaKeyFor(keyBytes);
    }

    /**
     * 如果 JWT_KEY 是 Base64 编码字符串（需确保解码后长度 ≥ 32 字节）：
     * @return
     */

    private SecretKey generalKey1() {
        // 1. 解码 Base64 密钥（确保解码后 ≥ 32 字节）
        byte[] encodedKey = Base64.getUrlDecoder().decode(JWT_KEY);

        // 2. 截取或填充到 32 字节（256 位）
        if (encodedKey.length < 32) {
            // 若不足，用 0 填充（不推荐，最好重新生成足够长的密钥）
            byte[] paddedKey = new byte[32];
            System.arraycopy(encodedKey, 0, paddedKey, 0, encodedKey.length);
            encodedKey = paddedKey;
        } else if (encodedKey.length > 32) {
            // 若过长，截取前 32 字节
            encodedKey = Arrays.copyOf(encodedKey, 32);
        }

        // 3. 生成符合 HS256 要求的密钥
        return Keys.hmacShaKeyFor(encodedKey);
    }


    /**
     * 解析 jwt
     * @param jwt
     * @return
     * @throws Exception
     */
    public Claims parseJWT(String jwt) throws Exception {
        SecretKey secretKey = generalKey();
        //主体解析
        return Jwts.parser()
                .verifyWith(secretKey)  // 0.12.x 新增 verifyWith 方法设置验证密钥
                .build()                 // 构建解析器
                .parseSignedClaims(jwt)  // 解析 JWT（返回 SignedClaims）
                .getPayload();           // 获取载荷

    }
}